home *** CD-ROM | disk | FTP | other *** search
/ MacTech 1 to 12 / MacTech-vol-1-12.toast / Source / MacTech® Magazine / Volume 11 - 1995 / 11.04 Apr 95 / TreeAppƒ / Eric's C++ Libraries / Interface Classes / CPPVisualTree.cp < prev    next >
Encoding:
Text File  |  1996-04-04  |  17.7 KB  |  653 lines  |  [TEXT/KAHL]

  1. /***************************************************** IMPLEMENTATION
  2.     DATE:    10/24/93
  3.     AUTHOR: Eric R. Rosé
  4.  
  5.     CLASS:  CPPVisualTree
  6.     
  7.     SUPERCLASS: CPPTree
  8.     
  9.         This C++ class handles the display of a tree by combining
  10.         CPPVisualObject with CPPTree
  11.     
  12. ********************************************************************/
  13.  
  14. #include <CPPWindow.h>
  15. #include <CPPVisualTree.h>
  16. #include <CPPVisualTreeNode.h>
  17. #include <Commands.h>
  18. #include <stdlib.h>
  19. #include <ToolboxTools.h>
  20.  
  21. extern    Rect    kEmptyRect;
  22.  
  23. /*-----------------------------------------------------------------*/
  24. /*------------------------ APPLY ROUTINES -------------------------*/
  25. /*-----------------------------------------------------------------*/
  26.  
  27.     void    SetSelectState (CPPTreeNode *theNode, long param)
  28.     /* set the selection state of the node according to the value */
  29.     /* passed in param; cause a redraw of the node */
  30.     {
  31.         if (theNode)
  32.           ((CPPVisualTreeNode *)theNode)->SetSelect((short)param, FALSE, TRUE);
  33.     }
  34.  
  35. /*-----------------------------------------------------------------*/
  36.  
  37.     void    DrawOrEraseJoin (CPPTreeNode *theNode, long param)
  38.     /* draw or erase the join leading from the node's parent to the */
  39.     /* node; param is a boolean; if TRUE, draw, else erase */
  40.     {
  41.         CPPVisualTreeNode *thisNode = (CPPVisualTreeNode *)theNode;
  42.         CPPVisualTreeNode *parentNode = (theNode) ? (CPPVisualTreeNode *)theNode->Parent : NULL;
  43.         Rect    emptyRect = {0,0,0,0};
  44.         
  45.         if (thisNode->notYetPlaced || (parentNode == NULL) || parentNode->notYetPlaced) return;
  46.         
  47.         if ((Boolean)param)
  48.           ((CPPVisualTreeNode *)theNode)->DrawJoin (parentNode, thisNode);
  49.         else
  50.           ((CPPVisualTreeNode *)theNode)->EraseJoin (parentNode, thisNode);
  51.     }    
  52.  
  53. /*-----------------------------------------------------------------*/
  54.     
  55.     void    BuildSelectedList (CPPTreeNode *theNode, long param)
  56.     /* if the passed node is selected, add it to a list passsed in param */
  57.     {
  58.         CPPObjectList    *theList = (CPPObjectList *)param;
  59.         
  60.         if (theNode && ((CPPVisualTreeNode *)theNode)->IsSelected())
  61.           theList->AppendItem(theNode);
  62.     }    
  63.     
  64. /*-----------------------------------------------------------------*/
  65. /*------------------------ PUBLIC METHODS -------------------------*/
  66. /*-----------------------------------------------------------------*/
  67.  
  68.     void    CPPVisualTree::DrawAllJoins (Boolean doDraw)
  69.     /* cause all of the joins in the tree to be drawn or erased */
  70.     {
  71.         ApplyToFamily (this->topNode, DrawOrEraseJoin, (long)doDraw);
  72.     }
  73.     
  74. /*-----------------------------------------------------------------*/
  75.  
  76.     CPPVisualTree::CPPVisualTree (WindowPtr itsWindow, 
  77.                                      Point        newTopLeft,
  78.                                      orientStyle orientation,
  79.                                   justStyle justification,
  80.                                   joinTypes join,
  81.                                   short branchLength) :
  82.                    CPPTree ()
  83.     {
  84.         this->theWindow = itsWindow;
  85.         
  86.         this->isPrepared = FALSE;
  87.         this->preparedBy = NULL;
  88.         this->SavePort = NULL;
  89.         
  90.         this->topLeft = newTopLeft;
  91.                 
  92.         this->orientation = orientation;
  93.         this->justification = justification;
  94.         this->whichJoin = join;
  95.         this->branchLength = branchLength;
  96.  
  97.         this->lastClicked = NULL;
  98.         this->lastClickTime = 0;
  99.         this->nodeMargin = 2;
  100.     }
  101.  
  102. /*-----------------------------------------------------------------*/
  103.  
  104.     CPPVisualTree::~CPPVisualTree (void)
  105.     {
  106.         
  107.     }
  108.  
  109. /*-----------------------------------------------------------------*/
  110.  
  111.     Boolean    CPPVisualTree::Member (char *className)
  112.     {
  113.         if (strcmp(className, CPPVisualTree::ClassName()) == 0)
  114.           return TRUE;
  115.         else
  116.           return CPPTree::Member(className);
  117.     }
  118.     
  119. /*-----------------------------------------------------------------*/
  120.  
  121.     char *CPPVisualTree::ClassName (void)
  122.     {
  123.         return "CPPVisualTree";
  124.     }
  125.  
  126. /*-----------------------------------------------------------------*/
  127.     
  128.     void    CPPVisualTree::Prepare (CPPObject *caller)
  129.     /* if the grafport has not been prepared, prepare it now */
  130.     {
  131.         if (!isPrepared)
  132.           {    
  133.             this->isPrepared = TRUE;
  134.             this->preparedBy = caller;
  135.             
  136.             if (this->theWindow)
  137.               {
  138.                 GetPort (&SavePort);
  139.                 SetPort (this->theWindow);
  140.                 UserSpecificPrepare();
  141.               }
  142.           }
  143.     }
  144.  
  145. /*-----------------------------------------------------------------*/
  146.  
  147.     void    CPPVisualTree::Restore (CPPObject *caller)
  148.     /* if the one who prepared us is giving us this command, restore */
  149.     /* the prior characteristics of the grafport */
  150.     {
  151.         if (this->isPrepared && this->preparedBy == caller)
  152.           {
  153.               UserSpecificRestore();
  154.               SetPort(SavePort);
  155.               this->isPrepared = FALSE;
  156.               this->preparedBy = NULL;
  157.           }    
  158.     }
  159.  
  160. /*-----------------------------------------------------------------*/
  161.     
  162.     void    CPPVisualTree::ForceRedraw (Boolean doErase)
  163.     /* Cause the tree to redraw itself; optionally erase it entirely */
  164.     /* first */
  165.     {
  166.         if (this->topNode)
  167.           {
  168.             if (doErase)
  169.               CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
  170.             CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
  171.           }
  172.     }
  173.  
  174. /*-----------------------------------------------------------------*/
  175.  
  176.     void    CPPVisualTree::ForceResize (Boolean doDraw)
  177.     /* have the entire tree recalculate its size; optionally have it */
  178.     /* erase itself before and redraw itself after calculation */
  179.     {
  180.         if (this->topNode)
  181.           {
  182.               if (doDraw)
  183.                 CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
  184.               
  185.               CPPTree::BroadcastMessage (kResizeFamily, NULL);
  186.               
  187.               if (doDraw)
  188.                 CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
  189.         }
  190.     }
  191.  
  192.  
  193. /*-----------------------------------------------------------------*/
  194.  
  195.     void    CPPVisualTree::ForceMove (Boolean doDraw, Point topLeft)
  196.     /* have the entire tree move itself; optionally have it erase */
  197.     /* itself before and redraw itself after calculation */
  198.     {
  199.         if (this->topNode)
  200.           {
  201.               if (doDraw)
  202.                 CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
  203.               
  204.               this->topLeft = topLeft;
  205.               CPPTree::BroadcastMessage (kMoveFamily, (void *)(&topLeft));
  206.               
  207.               if (doDraw)
  208.                 CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
  209.         }
  210.     }
  211.  
  212. /*-----------------------------------------------------------------*/
  213.  
  214.     void    CPPVisualTree::GetTreeBounds (Rect *itsBounds)
  215.     /* return the rectangle which describes the position of the tree */
  216.     {
  217.         Rect    tempRect;
  218.         
  219.         if (this->topNode)
  220.           topNode->GetFamilyBounds (itsBounds);
  221.         else
  222.           *itsBounds = kEmptyRect;
  223.     }
  224.  
  225. /*-----------------------------------------------------------------*/
  226.  
  227.     void    CPPVisualTree::AdjustTree (void)
  228.     /* This routine makes sure that the tree is pinned to the upper */
  229.     /* left hand corner of the tree, as specified by the user   */
  230.     {
  231.         Rect    tempRect;
  232.         
  233.         if (this->topNode)
  234.           topNode->GetFamilyBounds (&tempRect);
  235.           
  236.         if ((tempRect.left != this->topLeft.h) ||
  237.             (tempRect.top != this->topLeft.v))
  238.           ForceMove (TRUE, this->topLeft);
  239.     }
  240.  
  241. /*-----------------------------------------------------------------*/
  242.  
  243.     void    CPPVisualTree::Draw (void)
  244.     {
  245.         this->forceDraw = TRUE;
  246.         CPPTree::BroadcastMessage(kDrawFamily, (void *)TRUE);
  247.         this->forceDraw = FALSE;
  248.     }
  249.  
  250. /*-----------------------------------------------------------------*/
  251.  
  252.     void    CPPVisualTree::DrawPoint2Point (Point FromPt, Point ToPt)
  253.     /* Draw a direct line between the two passed-in points */
  254.     {
  255.         MoveTo (FromPt.h, FromPt.v);
  256.         LineTo (ToPt.h, ToPt.v);
  257.     }
  258.  
  259. /*-----------------------------------------------------------------*/
  260.  
  261.     void    CPPVisualTree::DrawRightAngle (Point FromPt, Point ToPt, 
  262.                                            orientStyle orientation)
  263.     /* Draw a right-angle join between the two passed-in points */
  264.     {
  265.         MoveTo (FromPt.h, FromPt.v);
  266.  
  267.         switch (orientation) {
  268.             case kLeft2Right :
  269.             case kRight2Left :
  270.                 LineTo (FromPt.h + (ToPt.h - FromPt.h) / 2, FromPt.v);
  271.                 LineTo (FromPt.h + (ToPt.h - FromPt.h) / 2, ToPt.v);
  272.                 break;
  273.                 
  274.             case kTopDown :
  275.             case kBottomUp:
  276.                 LineTo (FromPt.h, FromPt.v  + (ToPt.v - FromPt.v) / 2);
  277.                 LineTo (ToPt.h, FromPt.v + (ToPt.v - FromPt.v) / 2);
  278.                 break;
  279.         }
  280.     
  281.         LineTo (ToPt.h, ToPt.v);
  282.     }
  283.  
  284. /*-----------------------------------------------------------------*/
  285.  
  286.     void    CPPVisualTree::DrawDefaultJoin (CPPVisualTreeNode *FromNode, 
  287.                                             CPPVisualTreeNode *ToNode)
  288.     /* Use the orientation and join information to draw a join between */
  289.     /* the two passed-in nodes */ 
  290.     {
  291.         Point    FromTop, FromBottom, FromLeft, FromRight;
  292.         Point    ToTop, ToBottom, ToLeft, ToRight;
  293.         orientStyle    orient = this->orientation;
  294.         
  295.         FromNode->GetAnchorPoints (&FromLeft, &FromRight, &FromTop, &FromBottom);
  296.         ToNode->GetAnchorPoints (&ToLeft, &ToRight, &ToTop, &ToBottom);
  297.         
  298.         switch (this->whichJoin) {
  299.         
  300.             case kNoJoin : 
  301.             
  302.                 break;
  303.             
  304.             case kPointToPoint : 
  305.                 switch (orient) {
  306.                     case kLeft2Right :
  307.                         DrawPoint2Point (FromRight, ToLeft);
  308.                         break;
  309.                     case kRight2Left :
  310.                         DrawPoint2Point (FromLeft, ToRight);
  311.                         break;
  312.                     case kBottomUp:
  313.                         DrawPoint2Point (FromTop, ToBottom);
  314.                         break;
  315.                     case kTopDown :
  316.                         DrawPoint2Point (FromBottom, ToTop);
  317.                         break;
  318.                 }
  319.                 break;
  320.             
  321.             case kRightAngle : 
  322.                 switch (orient) {
  323.                     case kLeft2Right : 
  324.                         DrawRightAngle (FromRight, ToLeft, kLeft2Right);
  325.                         break;
  326.                     case kRight2Left :
  327.                         DrawRightAngle (FromLeft, ToRight, kRight2Left);
  328.                         break;
  329.                     case kTopDown     : 
  330.                         DrawRightAngle (FromBottom, ToTop, kTopDown);
  331.                         break;
  332.                     case kBottomUp    :
  333.                         DrawRightAngle (FromTop, ToBottom, kBottomUp);
  334.                         break;
  335.                 }
  336.                 break;
  337.         }
  338.     }
  339.  
  340. /*-----------------------------------------------------------------*/
  341.  
  342.     void    CPPVisualTree::SetBranchLength (short newLength)
  343.     /* Change the length of the branches of the tree */
  344.     {
  345.         if (this->branchLength != newLength)
  346.           {
  347.               this->Prepare(this);
  348.             CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
  349.             this->branchLength = newLength;
  350.             CPPTree::BroadcastMessage (kResizeFamily, NULL);
  351.             CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
  352.             this->Restore(this);
  353.           }
  354.     }
  355.  
  356. /*-----------------------------------------------------------------*/
  357.  
  358.     void    CPPVisualTree::SetNodeMargin (short newMargin)
  359.     /* change the amount of space between the tree's nodes */
  360.     {
  361.         if (this->nodeMargin != newMargin)
  362.           {
  363.               this->Prepare(this);
  364.             CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
  365.             this->nodeMargin = newMargin;
  366.             CPPTree::BroadcastMessage (kResizeFamily, NULL);
  367.             CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
  368.             this->Restore(this);
  369.           }
  370.     }
  371.  
  372. /*-----------------------------------------------------------------*/
  373.  
  374.     void    CPPVisualTree::SetOrientation (orientStyle newOrient)
  375.     /* switch the orientation of the tree from horiz to vert or vv */
  376.     {
  377.         if (this->orientation != newOrient)
  378.           {
  379.               this->Prepare(this);
  380.             CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
  381.             this->orientation = newOrient;
  382.             CPPTree::BroadcastMessage (kResizeFamily, NULL);
  383.             CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
  384.             this->Restore(this);
  385.           }
  386.     }
  387.  
  388. /*-----------------------------------------------------------------*/
  389.  
  390.     void    CPPVisualTree::SetJustification (justStyle newJust)
  391.     /* Switch the orientation to left, center, or right */
  392.     {
  393.         if (this->justification != newJust)
  394.           {
  395.               this->Prepare(this);
  396.             CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
  397.             this->justification = newJust;
  398.             CPPTree::BroadcastMessage (kResizeFamily, NULL);
  399.             CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
  400.             this->Restore(this);
  401.           }
  402.     }
  403.  
  404. /*-----------------------------------------------------------------*/
  405.  
  406.     void    CPPVisualTree::SetJoinType (joinTypes newJoin)
  407.     /* Change the join type to rightangle, none, or point2point */
  408.     {
  409.         if (this->whichJoin != newJoin)
  410.           {
  411.               this->Prepare(this);
  412.               DrawAllJoins (FALSE);
  413.             this->whichJoin = newJoin;
  414.               DrawAllJoins (TRUE);
  415.             this->Restore(this);
  416.           }
  417.     }
  418.  
  419. /*-----------------------------------------------------------------*/
  420.  
  421.     void    CPPVisualTree::DoCut (void)
  422.     /* cut the currently selected nodes of the tree */
  423.     /* SUBCLASS SHOULD OVERRIDE */
  424.     {
  425.         SysBeep(1);
  426.     }
  427.  
  428. /*-----------------------------------------------------------------*/
  429.  
  430.     void    CPPVisualTree::DoCopy (void)
  431.     /* copy the entire tree as a picture; store in the clipboard */
  432.     {
  433.         PicHandle    tempPict = GetTreePicture (TRUE, TRUE);
  434.         KillPicture (tempPict);
  435.     }
  436.  
  437. /*-----------------------------------------------------------------*/
  438.  
  439.     void    CPPVisualTree::DoPaste (void)
  440.     /* paste new data into the area */
  441.     /* SUBCLASS SHOULD OVERRIDE */
  442.     {
  443.         SysBeep(1);
  444.     }
  445.  
  446. /*-----------------------------------------------------------------*/
  447.  
  448.     void    CPPVisualTree::DoClear (void)
  449.     /* clear the currently selected nodes of the tree */
  450.     /* SUBCLASS SHOULD OVERRIDE */
  451.     {
  452.         CPPObjectList    *theList = new CPPObjectList();
  453.         CPPVisualTreeNode    *theNode = NULL;
  454.         
  455.         if (this->topNode)
  456.           {
  457.               ApplyToFamily (this->topNode, BuildSelectedList, (long)theList);
  458.               
  459.               // delete each node in the list in turn
  460.               for (long i = theList->GetNumItems(); i >= 1; i--)
  461.                 {
  462.                     theNode = (CPPVisualTreeNode *)((*theList)[i]);
  463.                     if (theNode)
  464.                       theNode->DeleteNode(theNode);
  465.                 }
  466.           }
  467.           
  468.         delete theList;
  469.     }
  470.  
  471. /*-----------------------------------------------------------------*/
  472.  
  473.     void    CPPVisualTree::DoSelectAll (void)
  474.     /* select the entire tree */
  475.     {
  476.          if (this->topNode)
  477.                ApplyToFamily(this->topNode, SetSelectState, kSetSelect);
  478.     }
  479.  
  480. /*-----------------------------------------------------------------*/
  481.  
  482.     Boolean    CPPVisualTree::DoCommand (short commandID)
  483.     /* do a command associated with a menu */
  484.     {
  485.         switch (commandID) {
  486.             case kCmdCut :
  487.                 DoCut();
  488.                 break;
  489.             case kCmdCopy :    
  490.                 DoCopy();
  491.                 break;
  492.             case kCmdPaste :
  493.                 DoPaste();
  494.                 break;
  495.             case kCmdSelectAll :
  496.                 DoSelectAll();
  497.                 break;
  498.             case kCmdClear :
  499.                 DoClear();
  500.                 break;
  501.             default:
  502.                 return FALSE;    // we are the first class with
  503.                 break;            // the 'DoCommand' method
  504.         }
  505.         
  506.         return TRUE;
  507.     }
  508.  
  509. /*-----------------------------------------------------------------*/
  510.  
  511.     Boolean    CPPVisualTree::DoTreeClick (EventRecord *theEvent)
  512.     {
  513.         Point    myPt = theEvent->where,
  514.                 startPt,
  515.                 endPt;
  516.         Rect    selRect;
  517.         CPPVisualTreeNode    *theNode;
  518.         Boolean    wasDoubleClick = FALSE;
  519.         GrafPtr    savePort;
  520.         
  521.         GetPort(&savePort);
  522.         SetPort(this->theWindow);
  523.         
  524.            GlobalToLocal (&myPt);
  525.            
  526.              // first, check to see if the click was in a node
  527.              if (theNode = ((CPPVisualTreeNode *)this->topNode)->PointInNode (myPt))
  528.                {
  529.                    // determine whether we have double-clicked on the node
  530.                    wasDoubleClick = (theNode == this->lastClicked) && 
  531.                                        (theEvent->when - this->lastClickTime <= GetDblTime());
  532.                    this->lastClicked = theNode;
  533.                    this->lastClickTime = theEvent->when;
  534.                    
  535.                    if (wasDoubleClick)
  536.                      theNode->DoDoubleClick (theEvent->modifiers);
  537.                    else
  538.                      {    // if the shift key is down, invert selection state
  539.                          if (ShiftKeyDown(theEvent->modifiers))
  540.                            theNode->SetSelect(kToggleSelect, FALSE, TRUE);
  541.                          else
  542.                          // if the command key is down, add to selection
  543.                          if (CommandKeyDown (theEvent->modifiers))
  544.                            theNode->SetSelect(kSetSelect, FALSE, TRUE);
  545.                          else
  546.                            {    // if no modifiers down, de-select all and select this one
  547.                                ApplyToFamily(this->topNode, SetSelectState, kClearSelect);
  548.                              theNode->SetSelect(kSetSelect, FALSE, TRUE);
  549.                            }
  550.                          theNode->DoSingleClick (theEvent->modifiers);
  551.                      }
  552.                    SetPort (savePort);
  553.                   return TRUE;
  554.                }
  555.              else    // the user did not click in a node.  De-select the current selection 
  556.                {        // if necessary, then return FALSE
  557.                    if (!ShiftKeyDown (theEvent->modifiers) && 
  558.                        !CommandKeyDown(theEvent->modifiers))
  559.                      ApplyToFamily(this->topNode, SetSelectState, kClearSelect);
  560.                    return FALSE;
  561.                }    // PtInRect
  562.              
  563.         SetPort(savePort);
  564.         return FALSE;
  565.     }
  566.  
  567. /*-----------------------------------------------------------------*/
  568.  
  569.     PicHandle    CPPVisualTree::GetTreePicture (Boolean asQDPICT, Boolean placeInClipboard)
  570.     /* Return a picture of the tree as either a bitmap or a */
  571.     /* quickdraw picture */
  572.     {
  573. #define    SetLineWidth 182
  574.  
  575.         typedef PointPtr *PointHndl;
  576.     
  577.         PicHandle    tempPict;
  578.         Rect        tempRect;
  579.         PointHndl    theWidth;
  580.         RgnHandle    OldClip, NewClip;
  581.         long        dummy;
  582.         
  583.         this->Prepare((CPPObject *)(1312L));
  584.         this->GetTreeBounds (&tempRect);
  585.         
  586.         if (asQDPICT)
  587.           {
  588.               // set the clipping region to be the area of the tree
  589.             OldClip = NewRgn();
  590.             NewClip = NewRgn();
  591.             GetClip (OldClip);
  592.             RectRgn (NewClip, &tempRect);
  593.             SetClip (NewClip);
  594.  
  595.             // set the line width to be 1/5 by 1/5
  596.             tempPict = OpenPicture (&tempRect);
  597.             theWidth = (PointHndl)(NewHandle(sizeof(Point)));
  598.             if (theWidth)
  599.               {
  600.                   SetPt (*theWidth, 5, 1);
  601.                 PicComment(SetLineWidth, sizeof(Point), (Handle)theWidth);
  602.               }
  603.             this->ForceRedraw(FALSE);    // draw without erasing the old tree
  604.             ClosePicture();
  605.             
  606.             // restore the old clipping region
  607.             SetClip(OldClip);
  608.             DisposeRgn(NewClip);
  609.             DisposeRgn(OldClip);
  610.           }
  611.         else
  612.           {
  613.               tempPict = OpenPicture(&tempRect);
  614.             CopyBits (&theWindow->portBits, &theWindow->portBits, &tempRect, 
  615.                       &tempRect, srcCopy, NULL);
  616.             ClosePicture();
  617.           }
  618.  
  619.         this->Restore((CPPObject *)(1312L));
  620.         
  621.         // if asked, place a copy in the clipboard before exiting
  622.         if (placeInClipboard)
  623.           {
  624.               HLock((Handle)tempPict);
  625.               dummy = ZeroScrap();
  626.               dummy = PutScrap (GetHandleSize((Handle)tempPict), 'PICT', (Ptr)(*tempPict));
  627.               HUnlock((Handle)tempPict);
  628.           }
  629.           
  630.         return tempPict;
  631.     }
  632.  
  633. /*-----------------------------------------------------------------*/
  634. /*---------------------- PROTECTED METHODS ------------------------*/
  635. /*-----------------------------------------------------------------*/
  636.  
  637.     void    CPPVisualTree::UserSpecificPrepare (void)
  638.     /* Perform any special setup of the grafport before drawing */
  639.     /* SUBCLASS MAY OVERRIDE */ 
  640.     {
  641.     
  642.     }
  643.  
  644. /*-----------------------------------------------------------------*/
  645.  
  646.     void    CPPVisualTree::UserSpecificRestore (void)
  647.     /* Perform any special restoration of the grafport after drawing */
  648.     /* SUBCLASS MAY OVERRIDE */ 
  649.     {
  650.     
  651.     }
  652.  
  653.